package main

import "fmt"

/*
函数的意义不用多说，它可以封装复用的代码逻辑，减少了代码冗余
函数的基本语法为
	func 函数名(形参1 形参1的类型,形参2 形参2的类型 ...) (返回值1 返回值1的类型,返回值2 返回值2的类型...){
		部分执行语句
		return 返回值列表(如果我们定义了返回值则需要返回数据，没有的话return只做方法的中止，返回数据时一定要与定制的返回值列表一致)
	}
注意！！！！！Go的方法不支持重载，也就是同一个包中不允许存在同名方法，就算返回值和参数都不一样
*/

func main() {
	//noReturn()
	//i := hasReturn()
	//fmt.Printf("hasReturn()返回地参数为：%d\n", i)
	//noArgs()
	//hasArgs(1000)
	//hasMoreArgs(1, 2, true)
	//fmt.Println(testDefer())
	//hasUncertainArgs(1,2,3,4,5,6,7,8)
	//noNameFunc()
	testCallBack(5, callBakc) //第二个参数就放入回调函数
}

func noReturn() {
	fmt.Println("调用了没有返回值的方法")
}

func hasReturn() int {
	fmt.Println("调用了有返回值的方法")
	return 100
}

func noArgs() {
	fmt.Println("调用了不需要参数的方法")
}

func hasArgs(n1 int) {
	fmt.Printf("调用了需要参数的方法，传入的参数为：%d\n", n1)
}

func hasMoreArgs(f1 int, f2 float64, f3 bool) {
	fmt.Printf("调用了多个参数的方法，传入的参数为:%d\t%f\t%b\n", f1, f2, f3)
}

func hasMorereturn() (r1 int, r2 float64, r3 bool) {
	return 1, 2, true
}

/**
 * 因为我们定义返回值及其返回值名称，实际上我们就不用再去定义他们了
 * 我们只需在方法中为他们赋值，在最后调用return，就会把返回值返回
 */
func returnNoName() (r1 int, r2 float64, r3 bool) {
	r1 = 1
	r2 = 2
	return //默认会将所有已经定义好的返回值都返回，因为方法生成时已经生成了同名的遍历，他们都有默认值，return就能把这些同名遍历都返回
}

func testDefer() (result int) {
	defer func(x int) { //这是匿名方法，匿名方法可访问上一层方法的所有变量
		fmt.Println("结果defer的匿名方法将0改为1", x)
		result++
	}(5) //对于defer的匿名方法，如果匿名方法需要参数，那么这个括号就是填入参数的位置，没有参数则可以不写这个括号
	fmt.Println("快返回0了")
	return
}

//不定长参数是一个slice
func hasUncertainArgs(args ...int) {
	for _, value := range args {
		fmt.Println(value)
	}
}

func noNameFunc() {
	a := func(x int) (y bool) { //调用匿名方法，可通过等号左边调用
		fmt.Println("调用了有参数有返回值的匿名方法")
		return x > 0
	}

	b := func() {
		fmt.Println("调用了无参数无返回值的匿名方法")
	}
	c := a(5)
	b()
	fmt.Println("两个匿名方法的返回值", c)

	xs := map[int]func() int{ //这相当于是个存方法的map
		1: func() int {
			return 1
		},
		2: func() int {
			return 2
		},
		3: func() int {
			return 3
		},
	}
	fmt.Println(xs[1]()) //map中的方法通过索引加括号进调用
}

func callBakc(x int) {
	fmt.Println("执行了回调函数，返回值为", x)
}

func testCallBack(y int, f func(int)) {
	f(y)
}
